/**
 * Copyright (C) 2011 Moss Computing <support@mosscomputing.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.oslef.format;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.oslef.csv.table.Row;
import org.oslef.csv.table.Table;
import org.oslef.csv.table.TableIterator;

/**
 * Merges the oslef data in memory and iterates over it. Only useful
 * if you can fit all the supporting details for the OSLEF data you want
 * to read in memory.
 */
public final class Reader implements Iterator<Loan>, Iterable<Loan> {
	
	private final Table loansTable;
	private final TableIterator loansIterator;
	private final Table historyTable;
	private final Table installmentsTable;
	
	private Map<String, List<Row>> installmentRecords;
	private Map<String, List<Row>> historyRecords;
	
	public Reader(File oslefDir) throws IOException {
		if (oslefDir == null) throw new NullPointerException();
		loansTable = new Table(new File(oslefDir, "loans.csv"));
		loansIterator = loansTable.iterator();
		historyTable = new Table(new File(oslefDir, "history.csv"));
		installmentsTable = new Table(new File(oslefDir, "installments.csv"));
	}

	public boolean hasNext() {
		return loansIterator.hasNext();
	}
	
	public Loan next() {
		
		if (installmentRecords == null) {
			installmentRecords = new HashMap<String, List<Row>>();
			
			System.out.println("Loading installment records");
			
			List<Row> list;
			for (Row row : installmentsTable) {
				String loanId = row.get(Constants.LOAN_ID);
				list = installmentRecords.get(loanId);
				if (list == null) {
					list = new ArrayList<Row>();
					installmentRecords.put(loanId, list);
				}
				list.add(row);
			}
		}
		
		if (historyRecords == null) {
			historyRecords = new HashMap<String, List<Row>>();
			
			System.out.println("Loading history records");
			
			List<Row> list;
			for (Row row : historyTable) {
				String loanId = row.get(Constants.LOAN_ID);
				list = historyRecords.get(loanId);
				if (list == null) {
					list = new ArrayList<Row>();
					historyRecords.put(loanId, list);
				}
				list.add(row);
			}
		}
		
		Row loanRow = loansIterator.next();
		Loan l = new Loan();
		l.loan = new MapRecord();
		read(loanRow, l.loan);
		
		List<Row> iRecords = installmentRecords.get(l.loan.get(Constants.LOAN_ID));
		if (iRecords == null) iRecords = new ArrayList<Row>();
		for (Row row : iRecords) {
			MapRecord r = new MapRecord();
			read(row, r);
			l.installments.add(r);
		}
		
		List<Row> hRecords = historyRecords.get(l.loan.get(Constants.LOAN_ID));
		if (hRecords == null) hRecords = new ArrayList<Row>();
		for (Row row : hRecords) {
			MapRecord r = new MapRecord();
			read(row, r);
			l.history.add(r);
		}
		
		return l;
	}
	
	private static void read(Row row, Record record) {
		for (String k : row.header()) {
			String v = row.get(k);
			if (StringUtil.nonEmpty(v)) record.put(k, v);
		}
	}
	
	public void remove() {
		throw new UnsupportedOperationException();
	}
	
	public Iterator<Loan> iterator() {
		return this;
	}
	
	public void close() throws IOException {
		loansIterator.close();
	}
}
